package com.sc.nft.controller;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sc.nft.annotation.UserLogin;
import com.sc.nft.annotation.WithoutSign;
import com.sc.nft.config.fulu.FuLuConfig;
import com.sc.nft.controller.request.*;
import com.sc.nft.dto.BindPaySendSmsVO;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.vo.GetPaySignVO;
import com.sc.nft.entity.vo.mall.MallPaymentMethodVO;
import com.sc.nft.entity.vo.mall.MallWalletPayVO;
import com.sc.nft.enums.PayMethodEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.helper.HfPayHelper;
import com.sc.nft.helper.HnaPayHelper;
import com.sc.nft.hna.form.BaseTransForm;
import com.sc.nft.pool.UserPool;
import com.sc.nft.service.ApiOrderDirectService;
import com.sc.nft.service.MallPayOrderService;
import com.sc.nft.service.PaymentMethodService;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.Result;
import com.sc.nft.util.HttpUtil;
import com.sc.nft.wrapper.RequestWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/pay/mall")
@Api(tags = "IP商城支付接口")
public class IPMallPaymentController {

    private final PaymentMethodService paymentMethodService;
    private final MallPayOrderService mallPayOrderService;
    private final Redisson redisson;
    private final ApiOrderDirectService apiOrderDirectService;
    private final HnaPayHelper hnaPayHelper;


    @ApiOperation(value = "获取支付方式", notes = "获取支付方式", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getPayMethods", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<List<MallPaymentMethodVO>> getPaymentMethods(@Valid @RequestBody PaymentMethodsRequest request) {
        return Result.success(paymentMethodService.getMallEffectPayment(request.getIsH5(),request.getActivityId()));
    }

    @ApiOperation(value = "IP商城余额支付", notes = "余额支付(IP商城)", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/mallWalletPay", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<MallWalletPayVO> mallWalletPay(@Valid @RequestBody WalletPayRequest request, HttpServletRequest httpServletRequest) throws GlobalException {

        UserInfo user = UserPool.getUser();

        if(!StrUtil.equals( request.getDealPwd(),user.getTransactionPassword())){
            return Result.fail(ErrorCode.PASSWORD_ERROR);
        }
        //校验是否是钱包支付
        if(request.getPaymentMethod() != PayMethodEnum.WALLET_PAY){
            return Result.fail(ErrorCode.PAY_METHOID_ERROR);
        }

        MallWalletPayVO mallWalletPayVO = new MallWalletPayVO();

        RLock lock = redisson.getLock(RedisKeyEnum.MALL_WALLET_PAY_LOCK.getKey() + request.getOrderId());
        try {
            boolean res = lock.tryLock(10, 10, TimeUnit.SECONDS);
            if (res) {
                mallWalletPayVO = mallPayOrderService.mallWalletPay(request.getPaymentMethod(), request.getOrderId(), user, ServletUtil.getClientIP(httpServletRequest));
            }else {
                return Result.fail(ErrorCode.LATER_TRY);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            throw new GlobalException("系统超时");
        } finally {
            lock.unlock();
        }
        return Result.success(mallWalletPayVO);
    }

    @ApiOperation(value = "IP商城绑卡支付发送短信(杉德)", notes = "绑卡支付发送短信", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/sandBindPaySendSms", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<BindPaySendSmsVO> sandMallBindPaySendSms(@Valid @RequestBody BindPaySendSmsRequest request, HttpServletRequest httpServletRequest) {
        Long id = mallPayOrderService.sandMallBindPaySendSms(request.getBankCardId(), request.getOrderId(), UserPool.getUser(), ServletUtil.getClientIP(httpServletRequest));
        BindPaySendSmsVO bindPaySendSmsVO = new BindPaySendSmsVO();
        bindPaySendSmsVO.setId(id);
        return Result.success(bindPaySendSmsVO);
    }

    @ApiOperation(value = "IP商城绑卡支付短信认证(杉德)", notes = "绑卡支付短信认证", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/sandMallBindPay", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result sandMallBindPay(@Valid @RequestBody BindPayRequest request) {
        mallPayOrderService.sandMallBindPay(request.getId(), request.getSmsCode(), UserPool.getUser());
        return Result.success();
    }

    @ApiOperation(value = "IP商城-连连绑卡支付发送短信", notes = "连连绑卡支付发送短信", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/llBindPaySendSms", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<BindPaySendSmsVO> llBindPaySendSms(@Valid @RequestBody BindPaySendSmsRequest request, HttpServletRequest httpServletRequest) {
        return Result.success(mallPayOrderService.llBindPaySendSms(request.getBankCardId(), request.getOrderId(), UserPool.getUser(), ServletUtil.getClientIP(httpServletRequest)));
    }

    @ApiOperation(value = "IP商城-连连绑卡支付短信验证", notes = "连连绑卡支付短信验证", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/llPayVerify", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<GetPaySignVO> llPayVerify(@Valid @RequestBody BindPayRequest request, HttpServletRequest httpServletRequest) {
        UserInfo user = UserPool.getUser();
        if(StrUtil.isBlank(request.getToken())){
            return Result.fail("token不能为空");
        }
        mallPayOrderService.llPayVerify(user,request.getId(),request.getToken(),request.getSmsCode());
        return Result.success();
    }


    @ApiOperation(value = "IP商城唤起支付", notes = "IP商城唤起支付", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getMallPay", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result getPay(@Valid @RequestBody PaymentRequest request, HttpServletRequest httpServletRequest) {
        return Result.success(mallPayOrderService.getMallPay(request.getPaymentMethod(), request.getOrderId(), UserPool.getUser(), ServletUtil.getClientIP(httpServletRequest),request.getMac(),request.getWebPay(),request.getJumpType()));
    }

    @ApiOperation(value = "汇付支付回调", notes = "汇付支付回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/HfNotify", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ApiIgnore
    @WithoutSign
    public String hfFastNotify(HttpServletRequest request) throws GlobalException {
        String result = URLDecoder.decode(new RequestWrapper(request).getBody(), Charset.defaultCharset());
        String str = HfPayHelper.parseResult(result.replaceAll("check_value=",""));
        log.info("huifu fast notify back {}", str);
        HfPayNotifyRequest hfReq = JSONObject.parseObject(str,HfPayNotifyRequest.class);
        if (StrUtil.equals(hfReq.getResp_code(), "C00000")&&StrUtil.equals(hfReq.getTrans_stat(),"S")) {
            mallPayOrderService.paySuccess(hfReq.getOrder_id(), DateTime.now(), str, PayMethodEnum.HF_FAST_PAY);
        }else {
            log.warn("order pay fail:{}", hfReq.getOrder_id());
        }
        return "SUCCESS";
    }


    @ApiOperation(value = "查询是否支付成功", notes = "查询是否支付成功", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getMallPayResult", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<MallWalletPayVO> getMallPayResult(@Valid @RequestBody OrderNoRequest request) {
        return Result.success(mallPayOrderService.getMallPayResult(request.getOrderNo()));
    }


    @ApiOperation(value = "IP商城衫德支付回调", notes = "衫德支付回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/sandMallFastNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String sandFastNotify(HttpServletRequest request) throws GlobalException {
        String result = URLDecoder.decode(new RequestWrapper(request).getBody(), Charset.defaultCharset());
        log.info("sand fast notify back {}", result);
        Map<String, String> params = analyticalParameters(result);
        String data = params.get("data");
        JSONObject head = JSON.parseObject(data).getJSONObject("head");
        JSONObject body = JSON.parseObject(data).getJSONObject("body");
        if (StrUtil.equals(head.getString("respCode"), "000000")) {
            mallPayOrderService.paySuccess(body.getString("orderCode"), DateTime.of(body.getString("payTime"), "yyyyMMddHHmmss"), result, PayMethodEnum.FAST_PAY);
        } else {
            log.warn("order pay fail:{}", body.getString("tradeNo"));
        }
        return "respCode=000000";
    }

    @ApiOperation(value = "连连支付回调", notes = "连连绑卡回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/paySuccessNotifyUrl", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String paySuccessNotifyUrl(HttpServletRequest request) throws GlobalException {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连支付回调参数：{}", req);
        if(StrUtil.equals(req.getString("txn_status"),"TRADE_SUCCESS")){
            JSONObject result = req.getJSONObject("orderInfo");
            RLock lock = redisson.getLock(RedisKeyEnum.PAY_SUCCESS_LOCK.getKey() + result.getString("txn_seqno"));
            try {
                boolean res = lock.tryLock(3,  TimeUnit.SECONDS);
                if (res) {
                    mallPayOrderService.paySuccess(result.getString("txn_seqno"),DateTime.of(result.getString("txn_time"), "yyyyMMddHHmmss"),result.toJSONString(),PayMethodEnum.LL_PAY);
                    return "Success";
                }else {
                    throw new GlobalException("系统超时");
                }
            } catch (InterruptedException e) {
                throw new GlobalException("系统超时");
            } finally {
                lock.unlock();
            }
        }
        return "FAIL";
    }


    @ApiOperation(value = "IP商城衫德退款回调", notes = "衫德支付回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/sandMallRefundFastNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String sandMallRefundFastNotify(HttpServletRequest request) throws GlobalException {
        String result = URLDecoder.decode(new RequestWrapper(request).getBody(), Charset.defaultCharset());
        log.info("sand fast notify back {}", result);
        Map<String, String> params = analyticalParameters(result);
        String data = params.get("data");
        JSONObject head = JSON.parseObject(data).getJSONObject("head");
        JSONObject body = JSON.parseObject(data).getJSONObject("body");
        if (StrUtil.equals(head.getString("respCode"), "000000")) {
            try {
                long time = DateTime.now().getTime();
                log.info("退款回调等待5秒  开始时间" + time);
                Thread.sleep(5000);
                log.info("退款回调等待5秒  结束时间" + StrUtil.toString(DateTime.now().getTime() - time));
                mallPayOrderService.refundSuccess(body.getString("orderCode"), body.getString("payTime"), result, PayMethodEnum.FAST_PAY);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        } else {
            log.warn("IP商城衫德退款回调:{}", body.getString("tradeNo"));
        }
        return "respCode=000000";
    }


    @ApiOperation(value = "汇付退款回调", notes = "汇付支付回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/HfRefundNotify", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ApiIgnore
    @WithoutSign
    public String HfRefundNotify(HttpServletRequest request) throws GlobalException {
        String result = URLDecoder.decode(new RequestWrapper(request).getBody(), Charset.defaultCharset());
        String str = HfPayHelper.parseResult(result.replaceAll("check_value=",""));
        log.info("IP商城汇付退款回调 {}", str);
        HfPayNotifyRequest hfReq = JSONObject.parseObject(str,HfPayNotifyRequest.class);
        if(StrUtil.equals(hfReq.getResp_code(), "C00000")){//退款没有getTrans_stat
            try {
                long time = DateTime.now().getTime();
                log.info("退款回调等待5秒  开始时间" + time);
                Thread.sleep(5000);
                log.info("退款回调等待5秒  结束时间" + StrUtil.toString(DateTime.now().getTime() - time));
                mallPayOrderService.refundSuccess(hfReq.getOrder_id(), DateTime.now().toString("yyyyMMddHHmmss"), str, PayMethodEnum.HF_FAST_PAY);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }else {
            log.warn("IP商城汇付退款回调:{}", hfReq.getOrder_id());
        }
        return "SUCCESS";
    }

    @PostMapping("/hnaRefundNotify")
    @ApiIgnore
    @WithoutSign
    public String refundNotify(HttpServletRequest request) throws GlobalException {
        log.info("-------------进入新生支付退款异步回调-------------");
        JSONObject jsonObject = (JSONObject) JSONObject.toJSON(HttpUtil.getFormData(request));
        hnaPayHelper.checkNotifySign(
                jsonObject, BaseTransForm.getNotifyVerifyDataByTranCode("T005", jsonObject));
        log.info("-------------新生支付退款回调参数：{}-------------", jsonObject.toJSONString());
        if ("0000".equals(jsonObject.getString("resultCode"))) {
            mallPayOrderService.refundSuccess(jsonObject.getString("ncountOrderId"), jsonObject.getString("tranFinishTime"), jsonObject.toJSONString(), PayMethodEnum.HNA_PAY);
            return "200";
        }
        return "fail";
    }

    @ApiOperation(value = "连连支付退款回调", notes = "连连绑卡回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/llRefundNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String llRefundNotify(HttpServletRequest request) throws GlobalException {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("-------------------------------------------");
        log.info("连连退款回调参数：{}", req);
        log.info("-------------------------------------------");
        if(StrUtil.equals(req.getString("txn_status"),"TRADE_SUCCESS")){
            JSONObject result = new JSONObject(req);
            log.info("OrderNo:{},payTime:{}",result.getString("accp_txno"),result.getString("finish_time"));
            try {
                mallPayOrderService.refundSuccess(result.getString("accp_txno"),result.getString("finish_time"),result.toJSONString(),PayMethodEnum.LL_PAY);
                return "Success";
            } catch (Exception e) {
                throw new GlobalException("系统超时");
            }
        }
        return "FAIL";
    }


    /**
     * 解析回调参数
     *
     * @param params
     * @return
     */
    public static Map<String, String> analyticalParameters(String params) {
        if (StrUtil.isNotBlank(params)) {
            Map<String, String> paramsMap = Maps.newHashMap();
            for (String str : params.split("&")) {
                String[] s = str.split("=");
                if (s.length == 2) {
                    paramsMap.put(s[0], s[1]);
                } else {
                    paramsMap.put(s[0], StrUtil.EMPTY);
                }
            }
            return paramsMap;
        }
        return null;
    }


    @ApiOperation(value = "直充订单充值结果回调", notes = "直充订单充值结果回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/flNotify", produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ApiIgnore
    @WithoutSign
    public String flNotify(HttpServletRequest request) throws GlobalException {
        log.info("直充订单充值结果回调======开始");
        String result = URLDecoder.decode(new RequestWrapper(request).getBody(), Charset.defaultCharset());
        JSONObject resultJson = JSON.parseObject(result);
        String resultSign = resultJson.remove("sign").toString();
        log.info("result:{}", result);
        char[] s = JSONObject.toJSONString(resultJson, SerializerFeature.WriteMapNullValue).toCharArray();
        Arrays.sort(s);
        String outputSignOriginalStr = new String(s) + FuLuConfig.appSecret;
        String sign = SecureUtil.md5(outputSignOriginalStr);
        if (!sign.equals(resultSign)) {
            // 非法回调
            return "fail";
        }
        // 处理
        String synchronizationOrderDirectResult = apiOrderDirectService.synchronizationOrderDirect(resultJson);
        log.info("直充订单充值结果回调======结束");
        return synchronizationOrderDirectResult;

    }


    public static void main(String[] args){
        String result = URLDecoder.decode("extend=&charset=UTF-8&data=%7B%22head%22%3A%7B%22version%22%3A%221.0%22%2C%22respTime%22%3A%2220240314114425%22%2C%22respCode%22%3A%22000000%22%2C%22respMsg%22%3A%22%E6%88%90%E5%8A%9F%22%7D%2C%22body%22%3A%7B%22marketProductNo%22%3A%22%22%2C%22mid%22%3A%226888804116995%22%2C%22orderCode%22%3A%2220240314114409238752098%22%2C%22tradeNo%22%3A%2220240314114409238752098%22%2C%22sandSerialNo%22%3A%22240314113807151000112098%22%2C%22clearDate%22%3A%2220240314%22%2C%22totalAmount%22%3A%22000000005990%22%2C%22orderStatus%22%3A%221%22%2C%22payTime%22%3A%2220240314114425%22%2C%22settleAmount%22%3A%22000000005990%22%2C%22buyerPayAmount%22%3A%22000000005990%22%2C%22discAmount%22%3A%22000000000000%22%2C%22txnCompleteTime%22%3A%2220240314114425%22%2C%22payOrderCode%22%3A%2220240314sdb76710000004845%22%2C%22accLogonNo%22%3A%221727617830085509120%22%2C%22accNo%22%3A%22200657*****7554%22%2C%22midFee%22%3A%22000000000012%22%2C%22extraFee%22%3A%22000000000000%22%2C%22specialFee%22%3A%22000000000000%22%2C%22plMidFee%22%3A%22000000000000%22%2C%22bankserial%22%3A%22%22%2C%22externalProductCode%22%3A%2200002046%22%2C%22cardNo%22%3A%22200657*****7554%22%2C%22creditFlag%22%3A%222%22%2C%22bid%22%3A%22%22%2C%22benefitAmount%22%3A%22000000000000%22%2C%22remittanceCode%22%3A%22%22%2C%22extend%22%3A%22%22%2C%22accountAmt%22%3A%22000000005990%22%2C%22masterAccount%22%3A%22200657000097554%22%7D%7D&sign=LVLJDCMOlG76h809DWwvS%2B3AJqqIYDdIvnnovGA26vuxOi%2FFzNC1ZJu84qcJtaGW0l8kO39tKpDRVGSHon1u6%2FtJ4YS19dQFkxgG5MZ1%2FzA3Tsg0Lw0ZG2FJRNfRDgsURJl7nHbYGFXmgFo2NA%2BJo8K434YsibDcwPBS3WJGRmkJ%2F7TL4TowAc%2Fl3ljDAVPMlkTX5eFMJU0O6cUATlhMxoc5BJmCah%2B1c6js967EGt%2FUsfDt5EuBVtjEqsyGjptgSEVsyutiASfO80h%2FS5ysyD61ZKGIERSLS4vRgcBdYcQ9VVKQ6u%2BDN%2FasV97FwzK8G6n06%2BhiPMxdODU%2BssNbmg%3D%3D&signType=01", Charset.defaultCharset());
        log.info("sand fast notify back {}", result);
        Map<String, String> params = analyticalParameters(result);
        String data = params.get("data");
        JSONObject head = JSON.parseObject(data).getJSONObject("head");
        JSONObject body = JSON.parseObject(data).getJSONObject("body");
    }

}


